#ifndef __EC11_H__
#define __EC11_H__

#include "soc/soc_gpio.h"
#include "plat/nonecopyable.h"
#include "device_def.h"
#include "buttondevice.h"
#include "soc/soc_gpio.h"
#include "soc/soc_exti.h"

/// @brief 
///   A 作为外部中断
///   B 作为方向判断
///   C 作为按键 [C在按键系统实现，不在这里实现]
///   因为外部中断容易被干扰，优先使用轮询模式
///   包含二级过滤：IO状态过滤，方向变化过滤
class EC11Button : public NoneCopyable
{
public:
    enum class TriggerMode
    {
        Exti = 0,
        Polling
    };

public:
    using ValueChangedCallBack = std::function<void(EC11Button &sender, int oldValue, int newValue)>;
    using RotationDirCallBack = std::function<void(EC11Button &sender, DeviceDirection dir)>;

public:
    explicit EC11Button();
    explicit EC11Button(GpioPortPin eca, GpioPortPin ecb, TriggerMode mode, GpioExtiDevId extiId = GpioExtiDevId::None);
    virtual ~EC11Button();

public:
    void SetInfo(GpioPortPin eca, GpioPortPin ecb, TriggerMode mode, GpioExtiDevId extiId);

    void SetScale(int value);
    int GetScale();
    void SetDivChanged(int value);
    int GetDivChanged();

    int GetCurrentPosition();
    int GetCurrentAngle();

    void Start();
    void Stop();

    void SetPostionZero();

    void SetValueChangedCallBack(const ValueChangedCallBack &&func);
    void SetDirChangedCallBack(const RotationDirCallBack &&func);

    static std::string DirToString(DeviceDirection dir);
    
public:
    int ReadValueFilter(const GpioPortPin &portPin);
    void RaiseExti();
    void ReadValuePolling();
    void HandleValue(int value);

private:
    void __Init();

private:
    enum class PollingState
    {
        Idle = 0,
        Delay
    };

private:
    GpioPortPin m_APort;
    GpioPortPin m_BPort;
    TriggerMode m_mode = TriggerMode::Polling;
    GpioExtiDevId m_extiId;

    int m_divChangedCount = 200; //是否分频触发
    int m_timeBaseCount = 0;
    PollingState m_pollState = PollingState::Idle;
    int m_delayCurrentMs = 0;
    int m_aPValue = 0;
    uint32_t m_prevExtiRaiseMs = 0; //前一个中断来的时候的ms [IO状态过滤]
    uint32_t m_prevChangedDirMs = 0;
    Timer m_timer;
    SOC_Exti m_exti;

    int m_scale = 32; //旋转一周的刻度
    DeviceDirection m_lastDir = DeviceDirection::None;
    int m_preReportPos = 0;
    int m_currentPos = 0;  //记录当前角度值
    float m_curretnFloatPos = 0;

    bool m_isInit = false;
    ValueChangedCallBack m_valueChangedCallBack = nullptr;
    RotationDirCallBack m_dirChanged = nullptr;
};

#endif // __EC11_H__
